/*
 * This file (AxParameterManager.java) is protected by the GNU GPL licence (v2). 
 * Please read the license.txt attached for further informations. 
 * 
 */

package artx.objects;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import artx.parameters.AxBoolParameter;
import artx.parameters.AxFloatParameter;
import artx.parameters.AxIntParameter;
import artx.parameters.AxParameter;
import artx.parameters.AxStringParameter;
import artx.utils.AxLog;

/**
 * Manage a list of parameters.
 * 
 * @author Xavier Gouchet
 * 
 */

public class AxParameterManager extends AxManager {

	/**
	 * Standard constructor.
	 * 
	 * @param file
	 *            xml file containing the parameters configuration
	 */
	public AxParameterManager(String file) {
		super();
		try {
			AxLog
					.Debug("AxParameterManager::AxParameterManager =>> Parsing source document \""
							+ file + "\"");
			// parsing objects
			DocumentBuilderFactory factory = DocumentBuilderFactory
					.newInstance();
			DocumentBuilder builder = factory.newDocumentBuilder();

			// Reading xml file
			File xml = new File(file);
			Document document = builder.parse(xml);

			// convert DOM to list
			Element root = document.getDocumentElement();
			if (root != null) {
				NodeList params = root.getChildNodes();
				for (int i = 0; i < params.getLength(); i++) {
					Node p = params.item(i);
					NamedNodeMap attrs = p.getAttributes();
					if (p.getNodeName().toLowerCase().equals("parameter")) {
						String value = p.getTextContent();
						String type = null;
						String name = null;
						for (int j = 0; j < attrs.getLength(); j++) {
							Node a = attrs.item(j);
							if (a.getNodeName().toLowerCase().equals("name")) {
								name = a.getTextContent().toLowerCase();
							}
							if (a.getNodeName().toLowerCase().equals("type")) {
								type = a.getTextContent().toLowerCase();
							}
						}
						this.AddParameter(type, name, value);
					}
				}
			}
		} catch (ParserConfigurationException pce) {
			AxLog.Error(pce.getMessage());
		} catch (SAXException se) {
			AxLog.Error("Error while parsing \"" + file + "\" : "
					+ se.getMessage());
		} catch (IOException ioe) {
			AxLog.Error("Error while parsing \"" + file + "\" : "
					+ ioe.getMessage());
		}
	}

	/**
	 * Adds a parameter with specified info.
	 * 
	 * @param type
	 *            type of parameter
	 * @param name
	 *            name of the parameter
	 * @return boolean whether the operation was successful
	 */
	public boolean AddParameter(String type, String name) {
		return this.AddParameter(type, name, "");
	}

	/**
	 * Adds a parameter with specified info.
	 * 
	 * @param type
	 *            type of parameter
	 * @param name
	 *            name of the parameter
	 * @param value
	 *            string value of the parameter
	 * @return boolean whether the operation was successful
	 */
	public boolean AddParameter(String type, String name, String value) {
		AxLog.Debug("AxParameterManager::AddParameter =>> adding " + type
				+ " parameter " + name + " (" + value + ")");
		if ((type != null) && (!type.isEmpty()) && (name != null)
				&& (!name.isEmpty())) {
			if (type.toLowerCase().equals("bool")) {
				return this.AddBooleanParameter(name, value);
			}
			if (type.toLowerCase().equals("string")) {
				return this.AddStringParameter(name, value);
			}
			if (type.toLowerCase().equals("int")) {
				return this.AddIntegerParameter(name, value);
			}
			if (type.toLowerCase().equals("float")) {
				return this.AddFloatParameter(name, value);
			}
		}
		return false;
	}

	/**
	 * Adds a boolean parameter with specified info.
	 * 
	 * @param name
	 *            name of the parameter
	 * @param value
	 *            string value of the parameter
	 * @return boolean whether the operation was successful
	 */
	public boolean AddBooleanParameter(String name, String value) {
		AxBoolParameter param = new AxBoolParameter(name, value);

		if (param != null) {
			this.RegisterElement(param);
			return true;
		}
		return false;
	}

	/**
	 * Adds a string parameter with specified info.
	 * 
	 * @param name
	 *            name of the parameter
	 * @param value
	 *            string value of the parameter
	 * @return boolean whether the operation was successful
	 */
	public boolean AddStringParameter(String name, String value) {
		AxStringParameter param = new AxStringParameter(name, value);

		if (param != null) {
			this.RegisterElement(param);
			return true;
		}
		return false;
	}

	/**
	 * Adds a float parameter with specified info.
	 * 
	 * @param name
	 *            name of the parameter
	 * @param value
	 *            string value of the parameter
	 * @return boolean whether the operation was successful
	 */
	public boolean AddFloatParameter(String name, String value) {
		AxFloatParameter param = new AxFloatParameter(name, value);

		if (param != null) {
			this.RegisterElement(param);
			return true;
		}
		return false;
	}

	/**
	 * Adds an integer parameter with specified info.
	 * 
	 * @param name
	 *            name of the parameter
	 * @param value
	 *            string value of the parameter
	 * @return boolean whether the operation was successful
	 */
	public boolean AddIntegerParameter(String name, String value) {
		AxIntParameter param = new AxIntParameter(name, value);

		if (param != null) {
			this.RegisterElement(param);
			return true;
		}
		return false;
	}

	/**
	 * Reset all parameters in the list.
	 */
	public void ResetAllParameters() {
		int size = this.objectList.size();
		for (int i = 0; i < size; i++) {
			AxParameter param = (AxParameter) this.objectList.get(i);
			if (param != null) {
				param.ResetValue();
			}
		}
	}

	/**
	 * Get the list of parameters.
	 * 
	 * @return the list of parameters
	 */
	public ArrayList<AxParameter> GetParameters() {
		ArrayList<AxParameter> result = new ArrayList<AxParameter>();
		for (int i = 0; i < this.objectList.size(); i++) {
			AxParameter param = (AxParameter) this.objectList.get(i);
			if (param != null) {
				result.add(param);
			}
		}
		return result;
	}
	
	/**
	 * Gets an element by its name.
	 * 
	 * @param name
	 *            name of the object to get
	 * @return the object if it exists, else null
	 */
	public AxParameter GetParameter(String name) {
		AxParameter param = null;
		try{
			param = (AxParameter) this.GetElement(name);
		} catch (ClassCastException ce){
			param = null;
			AxLog.Debug("AxParameter::GetParameter =>> can't cast object to AxParameter");
		}
		return param;
	}

}
